#include "expression_golden_sample.hpp"
#include "res_gen/ArrayExpressionJson.c"
#include "res_gen/ArrowFunctionExpressionJson.c"
#include "res_gen/AssignmentExpressionJson.c"   
#include "res_gen/AwaitExpressionJson.c"        
#include "res_gen/BinaryExpressionJson.c"       
#include "res_gen/CallExpressionJson.c"
#include "res_gen/ChainExpressionJson.c"        
#include "res_gen/ClassExpressionJson.c"        
#include "res_gen/ConditionalExpressionJson.c"  
#include "res_gen/FunctionExpressionJson.c"
#include "res_gen/IdentifierJson.c"
#include "res_gen/ImportExpressionJson.c"
#include "res_gen/LiteralJson.c"
#include "res_gen/LogicalExpressionJson.c"
#include "res_gen/MemberExpressionJson.c"
#include "res_gen/MetaPropertyJson.c"
#include "res_gen/NewExpressionJson.c"
#include "res_gen/ObjectExpressionJson.c"
#include "res_gen/SequenceExpressionJson.c"
#include "res_gen/TaggedTemplateExpressionJson.c"
#include "res_gen/TemplateLiteralJson.c"
#include "res_gen/ThisExpressionJson.c"
#include "res_gen/UnaryExpressionJson.c"
#include "res_gen/UpdateExpressionJson.c"
#include "res_gen/YieldExpressionJson.c"

#include <unordered_map>
#include <iostream>
#include <iomanip>
#include <fstream>

namespace cyclone::parser
{
        struct GoldenSample
    {
        std::string expresion;
        std::string goldenSample;
        /**
         * Some node is context-sensitive , and may only appear in specific context
         */
        std::string errorMsg="";
    };
    static std::unordered_map<EstreeExpression, GoldenSample> GoldenSampleHash = std::unordered_map<EstreeExpression, GoldenSample>{
        std::make_pair(EstreeExpression::ThisExpression, GoldenSample{"this.name='alex'", ThisExpressionJson}),
        std::make_pair(EstreeExpression::ArrayExpression, GoldenSample{"[ 12, c , 'c' , d.e ]", ArrayExpressionJson}),
        std::make_pair(EstreeExpression::ObjectExpression, GoldenSample{" obj = { name : 'ALex', age : 12.1 }", ObjectExpressionJson}),
        std::make_pair(EstreeExpression::FunctionExpression, GoldenSample{"const c = function simple( age ,  person = {} ){ return age + person.age; }",FunctionExpressionJson}),
        std::make_pair(EstreeExpression::ArrowFunctionExpression, GoldenSample{"let callBack = (input ) => {  console.log(input);  }", ArrowFunctionExpressionJson}),
        std::make_pair(EstreeExpression::YieldExpression, GoldenSample{"function* foo(index) {while (index < 2) {yield* index;index++;}}", YieldExpressionJson, "Can only appear in  generator function"}),
        std::make_pair(EstreeExpression::Literal, GoldenSample{"\"a\" + 'b' / 1.2 * 1e1 ** 3.23232- 1.3e-3", LiteralJson}),
        std::make_pair(EstreeExpression::UnaryExpression, GoldenSample{"+a -b + typeof c / !d  + delete e.f ", UnaryExpressionJson}),
        std::make_pair(EstreeExpression::UpdateExpression, GoldenSample{"++a + --b - --c", UpdateExpressionJson}),
        std::make_pair(EstreeExpression::BinaryExpression, GoldenSample{"a + b * c ** d", BinaryExpressionJson}),
        std::make_pair(EstreeExpression::AssignmentExpression, GoldenSample{"a=b=c=e=f", AssignmentExpressionJson}),
        std::make_pair(EstreeExpression::LogicalExpression, GoldenSample{"c= d&&c  + e||f + (m??n)", LogicalExpressionJson, "Logical expressions and coalesce expressions cannot be mixed. Wrap either by parentheses "}),
        std::make_pair(EstreeExpression::MemberExpression, GoldenSample{"a?.b['c'][1e-1].e", MemberExpressionJson}),
        std::make_pair(EstreeExpression::ConditionalExpression, GoldenSample{"c = a ?b :d", ConditionalExpressionJson}),
        std::make_pair(EstreeExpression::CallExpression, GoldenSample{"a = c.toString().toFloat()", CallExpressionJson}),
        std::make_pair(EstreeExpression::NewExpression, GoldenSample{"const a = new b( 1 , 'Alex')", NewExpressionJson}),
        std::make_pair(EstreeExpression::SequenceExpression, GoldenSample{"for(let i = 1 , k = 0;skipIf(i===3), i < 10 ; i ++ , k+=2)console.log(k)", SequenceExpressionJson}),
        std::make_pair(EstreeExpression::TemplateLiteral, GoldenSample{"let info = `AAA${name}BB${age}CCC`", TemplateLiteralJson}),
        std::make_pair(EstreeExpression::TaggedTemplateExpression, GoldenSample{"const query = gql`{firstName lastName}}`", TaggedTemplateExpressionJson}),
        std::make_pair(EstreeExpression::ClassExpression, GoldenSample{"const Foo = class {constructor() {}bar() {return 'Hello World!';}};", ClassExpressionJson}),
        std::make_pair(EstreeExpression::MetaProperty, GoldenSample{"function fool(){return new.target();}", MetaPropertyJson}),
        std::make_pair(EstreeExpression::Identifier, GoldenSample{" a,  b,   cc", IdentifierJson}),
        std::make_pair(EstreeExpression::AwaitExpression, GoldenSample{"async function test(){ await timer.timeout()}", AwaitExpressionJson}),
        std::make_pair(EstreeExpression::ImportExpression, GoldenSample{"var acorn = import('./acorn.js')", ImportExpressionJson}),
        std::make_pair(EstreeExpression::ChainExpression, GoldenSample{"const size =  person?.name?.length()", ChainExpressionJson}),

    };
    static const std::string INVALID = "INVALID";
    const std::string &ExpressionGoldenSample::expresion(EstreeExpression idx)
    {
        return GoldenSampleHash.end() == GoldenSampleHash.find(idx) ? INVALID : GoldenSampleHash[idx].expresion;
    }
    Json ExpressionGoldenSample::ast(EstreeExpression idx)
    {
        auto goldenSample = GoldenSampleHash.end() == GoldenSampleHash.find(idx) ? "" : GoldenSampleHash[idx].goldenSample;
        if (goldenSample.empty())
            return Json();
        //NOTE the json parser may not work while parsing too long string with google test
        return Json::parse(goldenSample);
    }

} // namespace cyclone::parser
